﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace IndustryControls.Utils
{
    public class Animation
    {
        private AnimationType animationType = AnimationType.EaseInOut;
        /// <summary>
        /// 设置动画类型
        /// </summary>
        public AnimationType AnimationType { get => animationType; set => animationType = value; }
        /// <summary>
        /// 设置动画持续时间
        /// </summary>
        public int Duration
        {
            get => duration;
            set => duration = value;
        }

        private int duration = 200;

        private int span = 10;

        private int version = 0;

        public event EventHandler<AnimationEventArgs> AnimationComing;

        public float GetEaseProgress(AnimationType ease_type, float linear_progress)
        {
            switch (ease_type)
            {
                case AnimationType.Linear:
                    return linear_progress;
                case AnimationType.BackEaseIn:
                    return AnimationMethod.BackEaseIn(linear_progress, 0, 1, duration);
                case AnimationType.BackEaseInOut:
                    return AnimationMethod.BackEaseInOut(linear_progress, 0, 1, duration);
                case AnimationType.BackEaseOut:
                    return AnimationMethod.BackEaseOut(linear_progress, 0, 1, duration);
                case AnimationType.BackEaseOutIn:
                    return AnimationMethod.BackEaseOutIn(linear_progress, 0, 1, duration);
                case AnimationType.BounceEaseIn:
                    return AnimationMethod.BounceEaseIn(linear_progress, 0, 1, duration);
                case AnimationType.BounceEaseInOut:
                    return AnimationMethod.BounceEaseInOut(linear_progress, 0, 1, duration);
                case AnimationType.BounceEaseOut:
                    return AnimationMethod.BounceEaseOut(linear_progress, 0, 1, duration);
                case AnimationType.BounceEaseOutIn:
                    return AnimationMethod.BounceEaseOutIn(linear_progress, 0, 1, duration);
                case AnimationType.CircEaseIn:
                    return AnimationMethod.CircEaseIn(linear_progress, 0, 1, duration);
                case AnimationType.CircEaseInOut:
                    return AnimationMethod.CircEaseInOut(linear_progress, 0, 1, duration);
                case AnimationType.CircEaseOut:
                    return AnimationMethod.CircEaseOut(linear_progress, 0, 1, duration);
                case AnimationType.CircEaseOutIn:
                    return AnimationMethod.CircEaseOutIn(linear_progress, 0, 1, duration);
                case AnimationType.CubicEaseIn:
                    return AnimationMethod.CubicEaseIn(linear_progress, 0, 1, duration);
                case AnimationType.CubicEaseInOut:
                    return AnimationMethod.CubicEaseInOut(linear_progress, 0, 1, duration);
                case AnimationType.CubicEaseOut:
                    return AnimationMethod.CubicEaseOut(linear_progress, 0, 1, duration);
                case AnimationType.CubicEaseOutIn:
                    return AnimationMethod.CubicEaseOutIn(linear_progress, 0, 1, duration);
                case AnimationType.ElasticEaseIn:
                    return AnimationMethod.ElasticEaseIn(linear_progress, 0, 1, duration);

                case AnimationType.ElasticEaseInOut:
                    return AnimationMethod.ElasticEaseInOut(linear_progress, 0, 1, duration);
                case AnimationType.ElasticEaseOut:
                    return AnimationMethod.ElasticEaseOut(linear_progress, 0, 1, duration);
                case AnimationType.ElasticEaseOutIn:
                    return AnimationMethod.ElasticEaseOutIn(linear_progress, 0, 1, duration);
                case AnimationType.ExpoEaseIn:
                    return AnimationMethod.ExpoEaseIn(linear_progress, 0, 1, duration);
                case AnimationType.ExpoEaseInOut:
                    return AnimationMethod.ExpoEaseInOut(linear_progress, 0, 1, duration);
                case AnimationType.ExpoEaseOut:
                    return AnimationMethod.ExpoEaseOut(linear_progress, 0, 1, duration);
                case AnimationType.ExpoEaseOutIn:
                    return AnimationMethod.ExpoEaseOutIn(linear_progress, 0, 1, duration);
                case AnimationType.QuadEaseIn:
                    return AnimationMethod.QuadEaseIn(linear_progress, 0, 1, duration);
                case AnimationType.QuadEaseInOut:
                    return AnimationMethod.QuadEaseInOut(linear_progress, 0, 1, duration);
                case AnimationType.QuadEaseOut:
                    return AnimationMethod.QuadEaseOut(linear_progress, 0, 1, duration);
                case AnimationType.QuadEaseOutIn:
                    return AnimationMethod.QuadEaseOutIn(linear_progress, 0, 1, duration);
                case AnimationType.QuartEaseIn:
                    return AnimationMethod.QuartEaseIn(linear_progress, 0, 1, duration);
                case AnimationType.QuartEaseInOut:
                    return AnimationMethod.QuartEaseInOut(linear_progress, 0, 1, duration);
                case AnimationType.QuartEaseOut:
                    return AnimationMethod.QuartEaseOut(linear_progress, 0, 1, duration);
                case AnimationType.QuartEaseOutIn:
                    return AnimationMethod.QuartEaseOutIn(linear_progress, 0, 1, duration);
                case AnimationType.QuintEaseIn:
                    return AnimationMethod.QuintEaseIn(linear_progress, 0, 1, duration);
                case AnimationType.QuintEaseInOut:
                    return AnimationMethod.QuintEaseInOut(linear_progress, 0, 1, duration);
                case AnimationType.QuintEaseOut:
                    return AnimationMethod.QuintEaseOut(linear_progress, 0, 1, duration);
                case AnimationType.QuintEaseOutIn:
                    return AnimationMethod.QuintEaseOutIn(linear_progress, 0, 1, duration);

                case AnimationType.SineEaseIn:
                    return AnimationMethod.SineEaseIn(linear_progress, 0, 1, duration);
                case AnimationType.SineEaseInOut:
                    return AnimationMethod.SineEaseInOut(linear_progress, 0, 1, duration);
                case AnimationType.SineEaseOut:
                    return AnimationMethod.SineEaseOut(linear_progress, 0, 1, duration);
                case AnimationType.SineEaseOutIn:
                    return AnimationMethod.SineEaseOutIn(linear_progress, 0, 1, duration);
                default:
                    return linear_progress;
            }
        }

        /// <summary>
        /// 动画开始
        /// </summary>
        public void AnimationStart()
        {
            int number = Interlocked.Increment(ref version);
            ThreadPool.QueueUserWorkItem(Start, number);
        }
        /// <summary>
        /// 动画结束
        /// </summary>
        public void AnimationStop()
        {
            Interlocked.Increment(ref version);
        }

        private void Start(object state)
        {
            try
            {
                int number = Convert.ToInt32(state);
                float timespan = duration / span;
                float currentTime = timespan;
                while (currentTime < duration)
                {
                    if (number != version)
                        break;
                    Thread.Sleep((int)timespan);
                    AnimationComing.Invoke(this, new AnimationEventArgs() { NowValue = GetEaseProgress(AnimationType, currentTime) });
                    currentTime += timespan;
                    if (currentTime >= duration)
                    {
                        Thread.Sleep((int)(duration-currentTime));
                        AnimationComing.Invoke(this, new AnimationEventArgs() { NowValue = GetEaseProgress(AnimationType, currentTime) });
                    }
                }

                Interlocked.Decrement(ref version);
            }
            catch
            {

            }
        }
    }

    public class AnimationEventArgs : EventArgs
    {
        public float NowValue;
    }
}


